package world.snowcrystal.dao;


import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;
import lombok.extern.log4j.Log4j2;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import world.snowcrystal.Enum.AuthorityEnum;
import world.snowcrystal.dao.typehandler.GrantedAuthorityTypeHandler;

import java.io.Serial;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;


/**
 * @author 天晴
 * @since 1.0
 */
@Log4j2
@Getter
@NoArgsConstructor
@TableName("t_user")
@AllArgsConstructor
public class UserAuthenticationDetails implements UserDetails {

    @Serial
    private static final long serialVersionUID = 1923L;


    /**
     * 用户名字段有唯一键
     *
     * @since 1.0
     */
    private String username;

    /**
     * 这里存放的是使用 BCrypt 加密后的密码
     *
     * @see org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
     * @since 1.0
     */
    private String password;

    private String uuid;

    private Long id;

    private Boolean isEnabled;
    private String email;


    private Boolean isAccountNonExpired;
    private Boolean isAccountNonLocked;
    private Boolean isCredentialsNonExpired;


    /**
     * 用户注册时的 IP 地址
     *
     * @since 1.0
     */
    private Integer userRegisterIp;

    @TableField(typeHandler = GrantedAuthorityTypeHandler.class)
    private List<GrantedAuthority> authorities = new ArrayList<>();


    public UserAuthenticationDetails(String username, String password,
                                     Collection<? extends GrantedAuthority> authorities) {
    }

    public UserAuthenticationDetails(String username, String password,
                                     boolean enabled, boolean accountNonExpired,
                                     boolean credentialsNonExpired,
                                     boolean accountNonLocked,
                                     Collection<? extends GrantedAuthority> authorities) {

    }

    /**
     * @return 点分十进制的 IPv4 字符串
     * @author 天晴
     * @since 1.0
     */
    public String getRegisterIpAsString() {
        return (userRegisterIp >>> 24) +
                "." +
                ((userRegisterIp & 0x00FFFFFF) >>> 16) +
                "." +
                ((userRegisterIp & 0x0000FFFF) >>> 8) +
                "." +
                (userRegisterIp & 0x000000FF);
    }

    @Override
    public String toString(){
        return username;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return authorities;
    }

    @Override
    public String getPassword() {
        return password;
    }

    @Override
    public String getUsername() {
        return username;
    }

    @Override
    public boolean isAccountNonExpired() {
        return isAccountNonExpired;
    }

    @Override
    public boolean isAccountNonLocked() {
        return isAccountNonLocked;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return isCredentialsNonExpired;
    }

    @Override
    public boolean isEnabled() {
        return isEnabled;
    }


    public void setPassword(String password) {
        Assert.notNull(password, "Password must not be null");
        this.password = password;
    }

    public void setUsername(String username) {
        Assert.notNull(username, "Username must not be null");
        this.username = username;
    }

    /**
     * @param roles 代表该用户拥有的所有权限，以 <code>ROLE_</code> 开始的字符串表示；
     *              可以直接使用枚举类 {@link AuthorityEnum}
     */
    public void setAuthorities(String... roles) {
        Assert.notNull(authorities, "Authorities must not be null");
        this.authorities.addAll(AuthorityUtils.createAuthorityList(roles));
    }

    public void setAuthorities(Collection<? extends GrantedAuthority> authorities) {
        Assert.notNull(authorities, "Authorities must not be null");
        this.authorities.addAll(authorities);
    }

    public void addAuthority(GrantedAuthority grantedAuthority) {
        Assert.notNull(grantedAuthority, "GrantedAuthority must not be null");
        this.authorities.add(grantedAuthority);
    }

    public void addAuthority(String authority) {
        Assert.notNull(authority, "Authority must not be null");
        this.authorities.add(new SimpleGrantedAuthority(authority));
    }

    public static int parseStringIpv4(String ip) {
        String[] split = StringUtils.tokenizeToStringArray(ip, ".");
        Assert.isTrue(split != null && split.length == 4, "IPv4 must have 4 parts");

        int part1 = Integer.parseInt(split[0]);
        int part2 = Integer.parseInt(split[1]);
        int part3 = Integer.parseInt(split[2]);
        int part4 = Integer.parseInt(split[3]);
        return (part1 << 24) + (part2 << 16) + (part3 << 8) + part4;

    }

    public static UserAuthenticationDetails createNewRegisteredUser(String username,
                                                                    String password,
                                                                    String email,
                                                                    String remoteIp
    ) {
        return new UserAuthenticationDetails(username, password, null, null, true
                , email,
                true, true, true, parseStringIpv4(remoteIp), List.of(new SimpleGrantedAuthority(AuthorityEnum.ROLE_USER.name())));
    }


}
